package vn.edu.hut.soict.translate.transform;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import vn.edu.hut.soict.alignment.BiDirectionalTokenAlignment;
import vn.edu.hut.soict.lienkate.parser.Connection;
import vn.edu.hut.soict.lienkate.parser.Linkage;
import vn.edu.hut.soict.translate.transform.utils.GrammaticalConstant;
import vn.edu.hut.soict.translate.transform.utils.GrammaticalNumber;
import vn.edu.hut.soict.translate.transform.utils.NounTransformUtils;
import vn.edu.hut.soict.translate.transform.utils.VerbTransformUtils;

public abstract class Transformer {
	protected List<String> sourceTokenList;
	protected List<String> destinationTokenList;
	protected List<String> inputTokenList;
	protected Linkage sourceLinkage;
	protected Linkage destinationLinkage;
	protected Linkage inputLinkage;

	protected BiDirectionalTokenAlignment alignmentParser;
	protected Map<Integer, Integer> inputToSourceMap;

	protected List<Connection> deletedConnections;

	public Transformer(InnerTransformer transformer) {
		sourceTokenList = transformer.viTokenList;
		destinationTokenList = transformer.enTokenList;
		inputTokenList = transformer.inputTokenList;
		sourceLinkage = transformer.viLinkage;
		destinationLinkage = transformer.enLinkage;
		inputLinkage = transformer.inputLinkage;
		alignmentParser = transformer.alignment;
		inputToSourceMap = transformer.inputToSourceMap;
		deletedConnections = new ArrayList<Connection>();
	}

	protected int findLeftConnection(Linkage linkage, int i, String type, Connection current) {
		for (Connection connection : linkage.getLink().get(i)) {
			if (connection.type().startsWith(type) && connection != current && !deletedConnections.contains(connection)) {
				return connection.right();
			}
		}
		return -1;
	}

	protected int findRightConnection(Linkage linkage, int i, String type, Connection current) {
		for (int j = 0; j < linkage.getLink().size(); j++) {
			LinkedList<Connection> links = linkage.getLink().get(j);
			for (Connection connection : links) {
				if (i == connection.right() && connection.type().startsWith(type) && connection != current && !deletedConnections.contains(connection)) {
					return j;
				}
			}
		}
		return -1;
	}

	protected void transformRecursively(int i) {
		for (Connection connection : destinationLinkage.getLink().get(i)) {
			leftToRightRecursiveTransform(i, connection);
		}

		for (int j = 0; j < i; j++) {
			LinkedList<Connection> links = destinationLinkage.getLink().get(j);
			for (Connection connection : links) {
				if (i == connection.right()) {
					rightToLeftRecursiveTransform(j, connection);
				}
			}
		}
	}

	protected void leftToRightRecursiveTransform(int i, Connection connection) {
		String type = connection.type();
		String baseWord = destinationTokenList.get(i);
		int j = connection.right();
		String connectedWord = destinationTokenList.get(j);

		if (type.startsWith("O")) {
			// Verb - object connection
			// We only need to consider the agreement between to be and object
			if (VerbTransformUtils.beForm(baseWord) != GrammaticalConstant.ERROR) {
				GrammaticalConstant numberBe = GrammaticalNumber.verbNumber(baseWord);
				GrammaticalConstant numberObject = GrammaticalNumber.nounOrPronounNumber(connectedWord);
				if (!GrammaticalNumber.isAgree(numberBe, numberObject)) {
					connectedWord = GrammaticalNumber.nounDecline(connectedWord, numberBe);
					destinationTokenList.set(j, connectedWord);
					transformRecursively(j);
				}
			}
		}
		else if (type.startsWith("S")) {
			// Subject - verb connection
//			GrammaticalConstant numberSubject = GrammaticalNumber.nounOrPronounNumber(baseWord);
//			GrammaticalConstant numberVerb = GrammaticalNumber.verbNumber(connectedWord);
			if (!GrammaticalNumber.isAgree(baseWord, connectedWord)) {
				connectedWord = GrammaticalNumber.verbConjugate(connectedWord, baseWord);
				destinationTokenList.set(j, connectedWord);
				transformRecursively(j);
			}

		}
		else if (type.startsWith("D")) {
			// Determiner - noun connection
			GrammaticalConstant numberDeterminer = GrammaticalNumber.determinerNumber(baseWord);
			GrammaticalConstant numberNoun = GrammaticalNumber.nounOrPronounNumber(connectedWord);
			if (!GrammaticalNumber.isAgree(numberDeterminer, numberNoun)) {
				connectedWord = GrammaticalNumber.nounDecline(connectedWord, numberDeterminer);
				destinationTokenList.set(j, connectedWord);
				transformRecursively(j);
			}
			else {
				String determiner = NounTransformUtils.fixArticleAgree(connectedWord, baseWord);
				if (determiner != baseWord) {
					destinationTokenList.set(i, determiner);
				}
			}
		}
	}

	protected void rightToLeftRecursiveTransform(int j, Connection connection) {
		String type = connection.type();
		String connectedWord = destinationTokenList.get(j);
		int i = connection.right();
		String baseWord = destinationTokenList.get(i);

		if (type.startsWith("O")) {
			// Verb - object connection
			// We only need to consider the agreement between to be and object
			if (VerbTransformUtils.beForm(connectedWord) != GrammaticalConstant.ERROR) {
				GrammaticalConstant numberBe = GrammaticalNumber.verbNumber(connectedWord);
				GrammaticalConstant numberObject = GrammaticalNumber.nounOrPronounNumber(baseWord);
				if (!GrammaticalNumber.isAgree(numberBe, numberObject)) {
					connectedWord = GrammaticalNumber.verbConjugate(connectedWord, numberObject);
					destinationTokenList.set(j, connectedWord);
					transformRecursively(j);
				}
			}
		}
		else if (type.startsWith("S")) {
			// Subject - verb connection
			GrammaticalConstant numberSubject = GrammaticalNumber.nounOrPronounNumber(connectedWord);
			GrammaticalConstant numberVerb = GrammaticalNumber.verbNumber(baseWord);
			if (!GrammaticalNumber.isAgree(connectedWord, baseWord)) {
				connectedWord = GrammaticalNumber.nounDecline(connectedWord, numberVerb);
				destinationTokenList.set(j, connectedWord);
				transformRecursively(j);
			}
		}
		else if (type.startsWith("D")) {
			// Determiner - noun connection
			GrammaticalConstant numberDeterminer = GrammaticalNumber.determinerNumber(connectedWord);
			GrammaticalConstant numberNoun = GrammaticalNumber.nounOrPronounNumber(baseWord);
			if (!GrammaticalNumber.isAgree(numberDeterminer, numberNoun)) {
				connectedWord = GrammaticalNumber.determinerDecline(connectedWord, numberNoun);
				destinationTokenList.set(j, connectedWord);
				transformRecursively(j);
			}
			else {
				String determiner = NounTransformUtils.fixArticleAgree(baseWord, connectedWord);
				if (determiner != connectedWord) {
					destinationTokenList.set(j, determiner);
				}
			}
		}
	}
}
